#!/usr/bin/env python
# encoding: utf-8
import pandas as pd
from utils.common import get_holidays, get_current_time_type, get_days_inter
from feature_set.base_feature import BaseFeature, RequstData
from feature_set.loan.un.loan_un_base_v3_1.loan_un_order_v3_1 import LoanUnOrderV3_1
from feature_set.loan.un.loan_un_base_v3_1.loan_un_ovdpayoff_v3_1 import LoanUnOvdPayoffV3_1
from feature_set.loan.un.loan_un_base_v3_1.loan_un_payoff_v3_1 import LoanUnPayoffV3_1
from feature_set.loan.un.loan_un_base_v3_1.loan_un_prepayoff_v3_1 import LoanUnPrePayoffV3_1


class LoanUnBaseV3_1(BaseFeature):
    def __init__(self):
        super().__init__()
        self.function_map = {
            'loan_order_features_v3_1': self.loan_order_features_v3_1,
            'loan_payoff_features_v3_1': self.loan_payoff_features_v3_1,
            'loan_pre_payoff_features_v3_1': self.loan_pre_payoff_features_v3_1,
            'loan_ovd_payoff_features_v3_1': self.loan_ovd_payoff_features_v3_1,
        }
        self.country_id = None

    def load_conf(self):
        """
        load config file
        Returns:

        """
        pass

    def load_request(self, request_data: RequstData):
        """
        get request data and format feature input data
        Args:
            request_data: input detail data

        Returns:
            format order and installment data
        """
        current_acq_channel = request_data.acq_channel
        current_order_id = request_data.order_id
        register_time = request_data.data_sources['user_info_1']['userInfo']['userRecord']['registerTime']
        if current_order_id!= 'null':
            product_info = request_data.data_sources.get('user_info_1', {}).get('productInfo', {})
            current_product_code = product_info['productCode'].lower() if product_info['productCode'] else ''
            current_loan_amount = int(product_info['amount']) if product_info['amount'] else 0
            current_apply_time = product_info['createTime']
        else:
            current_product_code = ''
            current_loan_amount = 0
            current_apply_time = request_data.apply_time

        current_info = {'current_apply_time': current_apply_time,
                        'current_acq_channel': current_acq_channel,
                        'current_order_id': current_order_id,
                        'current_loan_amount': current_loan_amount,
                        'current_product_code': current_product_code,
                        'register_time': register_time}
        # order data
        user_history_order = request_data.data_sources['order_data_a']
        if not user_history_order or user_history_order == []:
            user_history_order = pd.DataFrame(columns=['app_order_id',
                                                       'user_id',
                                                       'acq_channel',
                                                       'device_type',
                                                       'product_name',
                                                       'product_code',
                                                       'product_set_code',
                                                       'loan_amount',
                                                       'down_payment',
                                                       'user_name',
                                                       'id_card_number',
                                                       'phone_number',
                                                       'apply_time',
                                                       'product_info',
                                                       'status',
                                                       'new_old_user_status',
                                                       'create_time',
                                                       'update_time',
                                                       'submit_type'])

        else:
            user_history_order = pd.DataFrame(user_history_order)
        user_history_order = get_order_format(user_history_order=user_history_order,
                                              current_order_id=current_order_id,
                                              current_apply_time=current_apply_time,
                                              current_acq_channel=current_acq_channel,
                                              current_product_code=current_product_code,
                                              register_time=register_time,
                                              country_id=self.country_id)

        # installment data
        user_history_installment = request_data.data_sources['installments_data_a']
        if not user_history_installment or user_history_installment == []:
            user_history_installment = pd.DataFrame(columns=['user_id',
                                                             'acq_channel',
                                                             'app_order_id',
                                                             'contract_no',
                                                             'repayment_date',
                                                             'installment_num',
                                                             'installment_amount',
                                                             'principal',
                                                             'interest',
                                                             'cut_interest',
                                                             'service_fee',
                                                             'management_fee',
                                                             'overdue_interest',
                                                             'overdue_days',
                                                             'penalty',
                                                             'extension_fee',
                                                             'repaid_principal',
                                                             'repaid_interest',
                                                             'repaid_cut_interest',
                                                             'repaid_service_fee',
                                                             'repaid_management_fee',
                                                             'repaid_overdue_interest',
                                                             'repaid_penalty',
                                                             'discount_amount',
                                                             'waive_amount',
                                                             'settlement_type',
                                                             'extension_count',
                                                             'status',
                                                             'create_time',
                                                             'update_time',
                                                             'repaid_principal',
                                                             'repaid_interest',
                                                             'repaid_cut_interest',
                                                             'repaid_service_fee',
                                                             'repaid_management_fee',
                                                             'repaid_overdue_interest',
                                                             'repaid_penalty',
                                                             'discount_amount',
                                                             'waive_amount',
                                                             'ovd_days',
                                                             'bill_category', 'repaid_amt_sum'
                                                             ])
        else:
            user_history_installment = pd.DataFrame(user_history_installment)
            user_history_installment[['repaid_principal',
                                      'repaid_interest',
                                      'repaid_cut_interest',
                                      'repaid_service_fee',
                                      'repaid_management_fee',
                                      'repaid_overdue_interest',
                                      'repaid_penalty',
                                      'discount_amount',
                                      'waive_amount',
                                      'ovd_days',
                                      'bill_category', 'repaid_amt_sum']] = user_history_installment.apply(
                get_bill_data,
                axis=1,
                result_type='expand',
                args=(current_apply_time,))
        user_history_installment = get_installment_format(user_history_order,user_history_installment,current_apply_time,register_time)

        # contract data
        user_history_contract = pd.DataFrame(request_data.data_sources['contract_data_a'])
        rst_data = {'current_info': current_info,
                    'user_history_order': user_history_order,
                    'user_history_installment': user_history_installment,
                    'user_history_contract': user_history_contract}
        self.data = rst_data

    def loan_order_features_v3_1(self):
        return LoanUnOrderV3_1.get_features(country_id=self.country_id, rst_data=self.data)

    def loan_payoff_features_v3_1(self):
        return LoanUnPayoffV3_1.get_features(rst_data=self.data)

    def loan_pre_payoff_features_v3_1(self):
        return LoanUnPrePayoffV3_1.get_features(rst_data=self.data)

    def loan_ovd_payoff_features_v3_1(self):
        return LoanUnOvdPayoffV3_1.get_features(rst_data=self.data)


def get_order_format(user_history_order,current_order_id, current_apply_time,current_acq_channel,current_product_code, register_time, country_id=None):
    """
    order_df 用户所有订单
    current_apply_time varchar 当前申请时间
    register_time varchr 用户注册时间
    return:
        返回格式化后的所有订单数据
    """
    user_history_order['register_time'] = register_time
    user_history_order['current_apply_time'] = current_apply_time
    user_history_order['app_order_id'] = user_history_order.app_order_id.astype(str)
    user_history_order['user_id'] = user_history_order.user_id.astype(str)
    user_history_order['apply_time'] = user_history_order.apply_time.astype(str)
    user_history_order['app_type'] = user_history_order.acq_channel.apply(lambda x: 'self_app' if x == current_acq_channel else 'other_app')
    user_history_order['product_type'] = user_history_order.product_code.apply(lambda x: 'self_product' if x == current_product_code else 'other_product')
    user_history_order['order_day_inter'] = (pd.to_datetime(user_history_order['current_apply_time']) - pd.to_datetime(user_history_order['apply_time'])).dt.days  # 当前申请时间距离每笔订单申请时间
    user_history_order['reg_day_inter'] = (pd.to_datetime(user_history_order['apply_time']) - pd.to_datetime(user_history_order['register_time'])).dt.days  # 每笔申请时间距离注册时间的间隔
    user_history_order['week_day'] = user_history_order.apply_time.apply(lambda x: pd.to_datetime(x).weekday())
    user_history_order['time_type'] = user_history_order.apply_time.apply(lambda x: get_current_time_type(x))
    user_history_order['app_day'] = user_history_order.apply_time.apply(lambda x: x[:10])
    user_history_order['is_holiday'] = user_history_order.apply_time.apply(lambda x: get_holidays(country_id, x))
    user_history_order = user_history_order[(user_history_order.apply_time <= current_apply_time) & (user_history_order.app_order_id != current_order_id)]  # 不包含本单，但是包含本批次数据
    # 订单预排序
    user_history_order = user_history_order.sort_values(by='app_order_id', ascending=False)
    return user_history_order


def get_installment_format(user_history_order,user_history_installment,current_apply_time,register_time):
    user_history_installment['app_order_id'] = user_history_installment.app_order_id.astype(str)
    user_history_installment['user_id'] = user_history_installment.user_id.astype(str)
    user_history_installment['payoff_day_inter'] = (pd.to_datetime(current_apply_time) - pd.to_datetime(user_history_installment['update_time'])).dt.days  # 当前申请时间距离每次还清时间间隔
    user_history_installment['reg_day_inter'] = (pd.to_datetime(user_history_installment['update_time']) - pd.to_datetime(register_time)).dt.days  # 还清时间距离注册时间的间隔
    user_history_installment['payoff_day'] = user_history_installment.update_time.apply(lambda x: x[:10])
    tmp_order_df = user_history_order[['app_order_id', 'user_id', 'acq_channel', 'product_code', 'apply_time', 'status', 'app_type', 'product_type']]
    tmp_order_df = tmp_order_df.rename(columns={'status': 'order_status'})
    user_history_installment = tmp_order_df.merge(user_history_installment, on=['app_order_id', 'user_id', 'acq_channel'])
    user_history_installment = user_history_installment[(user_history_installment.apply_time != current_apply_time)&(user_history_installment.create_time < current_apply_time)]
    # 账单预排序
    user_history_installment = user_history_installment.sort_values(by='update_time', ascending=True)
    return user_history_installment


def get_bill_data(df, current_apply_time):
    bill_status = df['status']
    repaid_principal = df['repaid_principal']
    repaid_interest = df['repaid_interest']
    repaid_cut_interest = df['repaid_cut_interest']
    repaid_service_fee = df['repaid_service_fee']
    repaid_management_fee = df['repaid_management_fee']
    repaid_overdue_interest = df['repaid_overdue_interest']
    repaid_penalty = df['repaid_penalty']
    discount_amount = df['discount_amount']
    waive_amount = df['waive_amount']
    payoff_time = df['update_time']
    repayment_date = df['repayment_date']
    settlement_type = df['settlement_type']
    extension_count = df['extension_count']
    interest = df['interest']
    ovd_days = 0
    bill_category = ''
    # 对于未还清的订单,判断是逾期在贷还是未到还款日当前在贷
    if bill_status == 1 and extension_count == 0 and settlement_type != 2:
        if current_apply_time[:10] > repayment_date:
            bill_category = 'ovd_onloan'  # 逾期在贷
            ovd_days = get_days_inter(current_apply_time, repayment_date + ' 00:00:00')
        else:
            bill_category = 'onloan'  # 未到还款日的在贷
            ovd_days = 0
    if bill_status == 2 and extension_count == 0 and settlement_type != 2:  # 对于已经还清的账单，计算还清时间与回溯时间的差距 重新计算逻辑
        if current_apply_time >= payoff_time:  # 对于还清的账单判断还清类型
            ovd_days = get_days_inter(payoff_time, repayment_date + ' 00:00:00')
            if ovd_days == 0:
                bill_category = 'normal_payoff'  # 正常结清
            elif ovd_days > 0:
                bill_category = 'ovd_payoff'  # 逾期结清
            elif ovd_days < 0:
                bill_category = 'pre_payoff'  # 提前还清
        elif current_apply_time < payoff_time:  # 还清时间在当前申请时间之前的
            bill_status = 1
            repaid_principal = 0
            repaid_interest = 0
            repaid_cut_interest = 0
            repaid_service_fee = 0
            repaid_management_fee = 0
            repaid_overdue_interest = 0
            repaid_penalty = 0
            discount_amount = 0
            waive_amount = 0
            if current_apply_time[:10] > repayment_date:
                bill_category = 'ovd_onloan'  # 逾期在贷
                ovd_days = get_days_inter(current_apply_time, repayment_date + ' 00:00:00')
            else:
                bill_category = 'onloan'  # 未到还款日的在贷
                ovd_days = 0
    if extension_count == 0 and settlement_type == 2:  # 展期原始单只有展期费用
        bill_category = 'ext'
        ovd_days = 0
    if extension_count > 0:  # 针对展期单 计算逾期天数及类别
        if bill_status == 1:  # 当前展期仍逾期
            if current_apply_time[:10] > repayment_date:
                bill_category = 'ext_ovd_onloan'  # 展期逾期在贷
                ovd_days = get_days_inter(current_apply_time, repayment_date + ' 00:00:00')
            else:
                bill_category = 'ext_onloan'  # 未到还款日的的展期在贷
                ovd_days = 0
        if bill_status == 2:  # 展期逾期
            if current_apply_time >= payoff_time:  # 对于还清的账单判断还清类型
                ovd_days = get_days_inter(payoff_time, repayment_date + ' 00:00:00')
                if ovd_days == 0:
                    bill_category = 'ext_payoff'  # 展期正常结清
                elif ovd_days > 0:
                    bill_category = 'ext_ovd_payoff'  # 展期逾期结清
                elif ovd_days < 0:
                    bill_category = 'ext_pre_payoff'  # 展期提前还清
            elif current_apply_time < payoff_time:  # 还清时间在当前申请时间之前的
                bill_status = 1
                repaid_principal = 0
                repaid_interest = 0
                repaid_cut_interest = 0
                repaid_service_fee = 0
                repaid_management_fee = 0
                repaid_overdue_interest = 0
                repaid_penalty = 0
                discount_amount = 0
                waive_amount = 0
                if current_apply_time[:10] > repayment_date:
                    bill_category = 'ext_ovd_onloan'  # 展期逾期在贷
                    ovd_days = get_days_inter(current_apply_time, repayment_date + ' 00:00:00')
                else:
                    bill_category = 'ext_onloan'  # 未到还款日的在贷
                    ovd_days = 0
    if interest > 0:
        repaid_amt_sum = repaid_principal + repaid_interest + repaid_cut_interest + repaid_service_fee + repaid_management_fee + repaid_overdue_interest + repaid_penalty
    else:
        repaid_amt_sum = repaid_principal + repaid_interest + repaid_service_fee + repaid_management_fee + repaid_overdue_interest + repaid_penalty
    return repaid_principal, repaid_interest, repaid_cut_interest, repaid_service_fee, repaid_management_fee, repaid_overdue_interest, repaid_penalty, discount_amount, waive_amount, ovd_days, bill_category, repaid_amt_sum
